package top.jfunc.common.router;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * LFU(Least Frequently Used)：最不经常使用，频率/次数
 */
public class LFURouter<T, O> implements Router<T, O> {

    private final Map<T, Integer> lfuMap = new ConcurrentHashMap<>();
    private static long CACHE_VALID_TIME = 0;

    @Override
    public T select(List<T> toSelectedList, O otherParam) {
        return route(toSelectedList, otherParam);
    }

    public T route(List<T> toSelectedList, O otherParam) {

        // cache clear
        if (System.currentTimeMillis() > CACHE_VALID_TIME) {
            CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
            // put new
            for (T t: toSelectedList) {
                if (!lfuMap.containsKey(t) || lfuMap.get(t) >1000000 ) {
                    // 初始化时主动Random一次，缓解首次压力
                    lfuMap.put(t, new Random().nextInt(toSelectedList.size()));
                }
            }
        }



        // remove old
        List<T> delKeys = new ArrayList<>();
        for (T existKey: lfuMap.keySet()) {
            if (!toSelectedList.contains(existKey)) {
                delKeys.add(existKey);
            }
        }
        if (delKeys.size() > 0) {
            for (T delKey: delKeys) {
                lfuMap.remove(delKey);
            }
        }

        // load least userd count address
        List<Map.Entry<T, Integer>> lfuItemList = new ArrayList<>(lfuMap.entrySet());
        lfuItemList.sort(Map.Entry.comparingByValue());

        Map.Entry<T, Integer> addressItem = lfuItemList.get(0);
        T minT = addressItem.getKey();
        addressItem.setValue(addressItem.getValue() + 1);

        return addressItem.getKey();
    }
}
